/**
 ******************************************************************************
 * @file           : bsp_ds18b20.c
 * @brief          : DS18B20 Driver Implementation
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./Devices/DS18B20/bsp_ds18b20.h"
#include <string.h>

/* Private function prototypes -----------------------------------------------*/
static void ds18b20_gpio_init(void);
static void ds18b20_gpio_out(void);
static void ds18b20_gpio_in(void);
static void ds18b20_pin_set(uint8_t state);
static uint8_t ds18b20_pin_read(void);
static void ds18b20_delay_us(uint32_t us);
static DS18B20_Error_e ds18b20_reset(void);
static void ds18b20_write_byte(uint8_t data);
static uint8_t ds18b20_read_byte(void);
static uint8_t ds18b20_crc8(const uint8_t *data, uint8_t len);

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       初始化DS18B20
 */
DS18B20_Error_e ds18b20_init(void)
{
    DS18B20_Error_e ret;
    
    /* 初始化GPIO */
    ds18b20_gpio_init();
    
    /* 检测设备 */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        log_e("Device not found");
        return DS18B20_ERROR_NODEV;
    }
    
    /* 设置分辨率 */
    ds18b20_set_resolution(DS18B20_RESOLUTION);
    
    log_i("DS18B20 initialized");
    return DS18B20_OK;
}

/**
 * @brief       读取温度
 */
DS18B20_Error_e ds18b20_read_temperature(float *temperature)
{
    uint8_t scratchpad[9];
    int16_t temp_raw;
    uint8_t crc;
    DS18B20_Error_e ret;
    
    if (temperature == NULL)
    {
        return DS18B20_ERROR_PARAM;
    }
    
    /* 复位 */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        return ret;
    }
    
    /* 跳过ROM，启动转换 */
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);
    ds18b20_write_byte(DS18B20_CMD_CONVERT_T);
    
    /* 等待转换完成 */
    HAL_Delay(750);  /* 12位分辨率需要750ms */
    
    /* 复位 */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        return ret;
    }
    
    /* 跳过ROM，读取暂存器 */
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);
    ds18b20_write_byte(DS18B20_CMD_READ_SCRATCHPAD);
    
    /* 读取9字节数据 */
    for (uint8_t i = 0; i < 9; i++)
    {
        scratchpad[i] = ds18b20_read_byte();
    }
    
    /* CRC校验 */
    crc = ds18b20_crc8(scratchpad, 8);
    if (crc != scratchpad[8])
    {
        log_e("CRC error: calc=0x%02X, recv=0x%02X", crc, scratchpad[8]);
        return DS18B20_ERROR_CRC;
    }
    
    /* 计算温度 */
    temp_raw = (scratchpad[1] << 8) | scratchpad[0];
    *temperature = (float)temp_raw / 16.0f;
    
    log_d("Temperature: %.4f°C", *temperature);
    
    return DS18B20_OK;
}

/**
 * @brief       设置分辨率
 */
DS18B20_Error_e ds18b20_set_resolution(DS18B20_Resolution_e resolution)
{
    uint8_t config;
    DS18B20_Error_e ret;
    
    if (resolution > DS18B20_RES_12BIT)
    {
        return DS18B20_ERROR_PARAM;
    }
    
    /* 复位 */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        return ret;
    }
    
    /* 写入配置 */
    config = (resolution << 5) | 0x1F;
    
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);
    ds18b20_write_byte(DS18B20_CMD_WRITE_SCRATCHPAD);
    ds18b20_write_byte(0);       /* TH寄存器 */
    ds18b20_write_byte(0);       /* TL寄存器 */
    ds18b20_write_byte(config);  /* 配置寄存器 */
    
    /* 复制到EEPROM */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        return ret;
    }
    
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);
    ds18b20_write_byte(DS18B20_CMD_COPY_SCRATCHPAD);
    
    HAL_Delay(10);  /* 写入EEPROM需要时间 */
    
    log_i("Resolution set to %d bits", 9 + resolution);
    
    return DS18B20_OK;
}

/**
 * @brief       获取分辨率
 */
DS18B20_Error_e ds18b20_get_resolution(DS18B20_Resolution_e *resolution)
{
    uint8_t scratchpad[9];
    DS18B20_Error_e ret;
    
    if (resolution == NULL)
    {
        return DS18B20_ERROR_PARAM;
    }
    
    /* 复位 */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        return ret;
    }
    
    /* 读取暂存器 */
    ds18b20_write_byte(DS18B20_CMD_SKIP_ROM);
    ds18b20_write_byte(DS18B20_CMD_READ_SCRATCHPAD);
    
    for (uint8_t i = 0; i < 9; i++)
    {
        scratchpad[i] = ds18b20_read_byte();
    }
    
    /* 解析分辨率 */
    *resolution = (scratchpad[4] >> 5) & 0x03;
    
    return DS18B20_OK;
}

/**
 * @brief       读取ROM ID
 */
DS18B20_Error_e ds18b20_read_rom_id(uint8_t *rom_id)
{
    DS18B20_Error_e ret;
    
    if (rom_id == NULL)
    {
        return DS18B20_ERROR_PARAM;
    }
    
    /* 复位 */
    ret = ds18b20_reset();
    if (ret != DS18B20_OK)
    {
        return ret;
    }
    
    /* 读ROM命令 */
    ds18b20_write_byte(0x33);
    
    /* 读取8字节ROM */
    for (uint8_t i = 0; i < 8; i++)
    {
        rom_id[i] = ds18b20_read_byte();
    }
    
    log_d("ROM ID: %02X%02X%02X%02X%02X%02X%02X%02X",
          rom_id[0], rom_id[1], rom_id[2], rom_id[3],
          rom_id[4], rom_id[5], rom_id[6], rom_id[7]);
    
    return DS18B20_OK;
}

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       初始化GPIO
 */
static void ds18b20_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    DS18B20_GPIO_CLK_ENABLE();
    
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
    
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET);
}

static void ds18b20_gpio_out(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

static void ds18b20_gpio_in(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

static void ds18b20_pin_set(uint8_t state)
{
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, 
                      state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

static uint8_t ds18b20_pin_read(void)
{
    return HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
}

static void ds18b20_delay_us(uint32_t us)
{
    uint32_t ticks = us * (SystemCoreClock / 1000000);
    uint32_t told = SysTick->VAL;
    uint32_t tnow, tcnt = 0;
    
    while (tcnt < ticks)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            tcnt += (tnow < told) ? (told - tnow) : (SysTick->LOAD - tnow + told);
            told = tnow;
        }
    }
}

/**
 * @brief       复位脉冲
 */
static DS18B20_Error_e ds18b20_reset(void)
{
    uint8_t timeout;
    
    ds18b20_gpio_out();
    ds18b20_pin_set(0);
    ds18b20_delay_us(480);
    
    ds18b20_pin_set(1);
    ds18b20_gpio_in();
    ds18b20_delay_us(60);
    
    timeout = DS18B20_TIMEOUT_US;
    while (ds18b20_pin_read() && timeout--)
    {
        ds18b20_delay_us(1);
    }
    
    if (timeout == 0)
    {
        return DS18B20_ERROR_NODEV;
    }
    
    ds18b20_delay_us(240);
    
    return DS18B20_OK;
}

/**
 * @brief       写入一个字节
 */
static void ds18b20_write_byte(uint8_t data)
{
    uint8_t i;
    
    ds18b20_gpio_out();
    
    for (i = 0; i < 8; i++)
    {
        ds18b20_pin_set(0);
        ds18b20_delay_us(2);
        
        if (data & 0x01)
        {
            ds18b20_pin_set(1);
        }
        
        ds18b20_delay_us(60);
        ds18b20_pin_set(1);
        ds18b20_delay_us(2);
        
        data >>= 1;
    }
}

/**
 * @brief       读取一个字节
 */
static uint8_t ds18b20_read_byte(void)
{
    uint8_t i, data = 0;
    
    for (i = 0; i < 8; i++)
    {
        data >>= 1;
        
        ds18b20_gpio_out();
        ds18b20_pin_set(0);
        ds18b20_delay_us(2);
        ds18b20_pin_set(1);
        ds18b20_delay_us(2);
        
        ds18b20_gpio_in();
        ds18b20_delay_us(10);
        
        if (ds18b20_pin_read())
        {
            data |= 0x80;
        }
        
        ds18b20_delay_us(50);
    }
    
    return data;
}

/**
 * @brief       CRC8校验
 */
static uint8_t ds18b20_crc8(const uint8_t *data, uint8_t len)
{
    uint8_t crc = 0;
    uint8_t i, j;
    
    for (i = 0; i < len; i++)
    {
        crc ^= data[i];
        
        for (j = 0; j < 8; j++)
        {
            if (crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x8C;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    
    return crc;
}
